
package atm.components.mock;

import java.util.ArrayList;
import java.util.HashMap;

import atm.components.Bank;
import atm.model.CreditCardInfo;
import atm.model.CreditCardVerificationStatus;
import atm.model.PinCodeVerificationStatus;

/**
 * This is just a mock class, that implements Bank interface so that it is easier to check if the rest of our code complies with the
 * interface. In real world this class would not be a part of implementation in that way, more likely it would be a client for a remote web
 * service.
 */
public class BankMock implements Bank {

	private HashMap<String, String> knownCrediCards;

	private ArrayList<String> blockedCreditCards;

	private HashMap<String, Integer> authorizationLimits;

	private HashMap<String, Integer> pinEntryCount;

	public BankMock() {
		setKnownCrediCards(new HashMap<String, String>());
		setBlockedCreditCards(new ArrayList<String>());
		setAuthorizationLimits(new HashMap<String, Integer>());
		setPinEntryCount(new HashMap<String, Integer>());

		// Create some mock values... So we can test the ATM
		getKnownCrediCards().put("1111-1111-1111-1111", "1111");
		getKnownCrediCards().put("2222-2222-2222-2222", "2222");
		getKnownCrediCards().put("3333-4444-5555-6666", "6543");
		getKnownCrediCards().put("1234-4321-5678-8756", "5852");
		getKnownCrediCards().put("6465-8756-325-8444", "9317");

		getBlockedCreditCards().add("9999-9999-9999-9999");
		getBlockedCreditCards().add("2525-2525-2525-2525");

		getAuthorizationLimits().put("1111-1111-1111-1111", 20000);
		getAuthorizationLimits().put("2222-2222-2222-2222", 1000);
		getAuthorizationLimits().put("3333-4444-5555-6666", 500);
		getAuthorizationLimits().put("1234-4321-5678-8756", 500000);
		getAuthorizationLimits().put("6465-8756-325-8444", 2000);
	}

	public HashMap<String, Integer> getAuthorizationLimits() {
		return authorizationLimits;
	}

	public ArrayList<String> getBlockedCreditCards() {
		return blockedCreditCards;
	}

	public HashMap<String, String> getKnownCrediCards() {
		return knownCrediCards;
	}

	public HashMap<String, Integer> getPinEntryCount() {
		return pinEntryCount;
	}

	private void setAuthorizationLimits(HashMap<String, Integer> value) {
		authorizationLimits = value;
	}

	private void setBlockedCreditCards(ArrayList<String> value) {
		blockedCreditCards = value;
	}

	private void setKnownCrediCards(HashMap<String, String> value) {
		knownCrediCards = value;
	}

	private void setPinEntryCount(HashMap<String, Integer> value) {
		pinEntryCount = value;
	}

	@Override
	public boolean verifyConnection() {
		// We can assume that bank is always available :)
		return true;
	}

	@Override
	public CreditCardVerificationStatus verifyCreditCard(CreditCardInfo creditCardInfo) {
		if (creditCardInfo != null && getBlockedCreditCards() != null && getKnownCrediCards() != null) {

			if (getBlockedCreditCards().contains(creditCardInfo.getNumber())) {
				return CreditCardVerificationStatus.BLOCKED;
			}

			return getKnownCrediCards().containsKey(creditCardInfo.getNumber()) ? CreditCardVerificationStatus.OK
			        : CreditCardVerificationStatus.INVALID;
		}
		throw new RuntimeException();
	}

	@Override
	public PinCodeVerificationStatus verifyPinCode(String creditCardNumber, String pinCode) {
		if (getKnownCrediCards() == null)
			throw new IllegalStateException("Known Credit cards are null");

		String savedPinCode = "";
		savedPinCode = getKnownCrediCards().get(creditCardNumber);

		if (savedPinCode.equals(pinCode)) {
			getPinEntryCount().remove(creditCardNumber);
			return PinCodeVerificationStatus.OK;
		} else {
			if (getPinEntryCount().containsKey(creditCardNumber)) {
				getPinEntryCount().put(creditCardNumber, getPinEntryCount().get(creditCardNumber) + 1);
				if (getPinEntryCount().get(creditCardNumber) > 3) {
					return PinCodeVerificationStatus.FAILED_CARD_LOCKED;
				}
			} else {
				getPinEntryCount().put(creditCardNumber, 1);
			}
			return PinCodeVerificationStatus.FAILED;
		}

	}

	@Override
	public boolean withdrawAmount(String creditCardNumber, String pinCode, int amount) {
		if (getAuthorizationLimits() == null)
			throw new IllegalStateException("Authorization limits is null");

		if (getAuthorizationLimits().containsKey(creditCardNumber)
		        && verifyPinCode(creditCardNumber, pinCode) == PinCodeVerificationStatus.OK) {
			return getAuthorizationLimits().get(creditCardNumber) >= amount;
		} else {
			return false;
		}

	}
}
